package com.powernode.driver.service.impl;

import com.powernode.common.constant.SystemConstant;
import com.powernode.common.execption.PowerException;
import com.powernode.common.result.ResultCodeEnum;
import com.powernode.common.util.LocationUtil;
import com.powernode.dispatch.client.NewOrderFeignClient;
import com.powernode.driver.service.OrderService;
import com.powernode.map.client.LocationFeignClient;
import com.powernode.map.client.MapFeignClient;
import com.powernode.model.entity.order.OrderInfo;
import com.powernode.model.form.map.CalculateDrivingLineForm;
import com.powernode.model.form.order.OrderFeeForm;
import com.powernode.model.form.order.StartDriveForm;
import com.powernode.model.form.order.UpdateOrderBillForm;
import com.powernode.model.form.order.UpdateOrderCartForm;
import com.powernode.model.form.rules.FeeRuleRequestForm;
import com.powernode.model.form.rules.ProfitsharingRuleRequestForm;
import com.powernode.model.form.rules.RewardRuleRequestForm;
import com.powernode.model.vo.map.DrivingLineVo;
import com.powernode.model.vo.map.OrderLocationVo;
import com.powernode.model.vo.order.CurrentOrderInfoVo;
import com.powernode.model.vo.order.NewOrderDataVo;
import com.powernode.model.vo.order.OrderInfoVo;
import com.powernode.model.vo.rules.FeeRuleResponseVo;
import com.powernode.model.vo.rules.ProfitsharingRuleResponseVo;
import com.powernode.model.vo.rules.RewardRuleResponseVo;
import com.powernode.order.client.OrderInfoFeignClient;
import com.powernode.rules.client.FeeRuleFeignClient;
import com.powernode.rules.client.ProfitsharingRuleFeignClient;
import com.powernode.rules.client.RewardRuleFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;

/**
 * 订单服务实现类
 * 提供订单相关的业务逻辑实现，包括查询订单状态、抢单、获取订单详情、计算最佳驾驶线路等
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;//订单服务Feign客户端
    @Resource
    private NewOrderFeignClient newOrderFeignClient;//新订单服务Feign客户端
    @Resource
    private MapFeignClient mapFeignClient;//地图服务Feign客户端
    @Resource
    private LocationFeignClient locationFeignClient;//位置服务Feign客户端
    @Resource
    private FeeRuleFeignClient feeRuleFeignClient;//费用规则服务Feign客户端
    @Resource
    private RewardRuleFeignClient rewardRuleFeignClient;//奖励规则服务Feign客户端
    @Resource
    private ProfitsharingRuleFeignClient profitsharingRuleFeignClient;//利润分享规则服务Feign客户端

    /**
     * 查询订单状态
     *
     * @param orderId 订单ID
     * @return 订单状态
     */
    @Override
    public Integer queryOrderStatus(Long orderId) {
        return orderInfoFeignClient.getOrderStatus(orderId).getData();
    }

    /**
     * 查询配送员新队列订单数据
     *
     * @param driverId 配送员ID
     * @return 新队列订单数据
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        return newOrderFeignClient.findNewOrderQueueData(driverId).getData();
    }

    /**
     * 查询配送员当前订单
     *
     * @param driverId 配送员ID
     * @return 当前订单信息
     */
    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        return orderInfoFeignClient.searchDriverCurrentOrder(driverId).getData();
    }

    /**
     * 根据订单ID和客户ID获取订单详情信息
     * 该方法会验证当前配送员是否有权限查看指定订单
     *
     * @param orderId  订单ID，用于查询具体的订单信息
     * @param driverId 配送员ID，用于验证订单所有权
     * @return OrderInfoVo 订单信息视图对象，包含订单的详细信息
     * @throws PowerException 当配送员尝试访问不属于自己的订单时抛出非法请求异常
     */
    @Override
    public OrderInfoVo getOrderInfo(Long orderId, Long driverId) {
        // 通过Feign客户端调用订单服务，获取订单详细信息
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();
        // 权限校验：确保当前客户只能查看自己的订单，比较订单所属客户ID与传入的客户ID是否一致
        if (orderInfo.getDriverId().longValue() != driverId.longValue()) {
            // 如果不一致，抛出非法请求异常
            throw new PowerException(ResultCodeEnum.ILLEGAL_REQUEST);
        }

        // 创建订单信息视图对象（VO），用于封装返回给前端的数据
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 使用BeanUtils工具将orderInfo的属性值复制到orderInfoVo中
        // 这一步会自动映射同名属性
        BeanUtils.copyProperties(orderInfo, orderInfoVo);
        // 显式设置订单ID，确保ID正确设置
        orderInfoVo.setOrderId(orderId);

        // 返回封装好的订单信息视图对象
        return orderInfoVo;
    }

    /**
     * 计算最佳驾驶线路
     *
     * @param calculateDrivingLineForm 包含订单ID和当前位置的表单数据
     * @return 最佳驾驶线路信息
     */
    @Override
    public DrivingLineVo calculateDrivingLine(CalculateDrivingLineForm calculateDrivingLineForm) {
        return mapFeignClient.calculateDrivingLine(calculateDrivingLineForm).getData();
    }

    /**
     * 配送员到达配送起始地点
     *
     * @param orderId  订单ID
     * @param driverId 配送员ID
     * @return 是否到达起始地点
     */
    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        /*
        // 调用订单信息Feign客户端，通过订单ID获取订单详细信息
        // getData()方法从响应结果中提取具体的OrderInfo数据
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();

        // 调用位置信息Feign客户端，获取缓存的订单位置信息
        // 该信息包含配送员当前的位置坐标
        OrderLocationVo orderLocationVo = locationFeignClient.getCacheOrderLocation(orderId).getData();

        // 计算配送员当前位置与订单起始点位置之间的距离
        // 参数1-2：订单起始点的纬度和经度（转换为double类型）
        // 参数3-4：配送员当前位置的纬度和经度（转换为double类型）
        double distance = LocationUtil.getDistance(orderInfo.getStartPointLatitude().doubleValue(), orderInfo.getStartPointLongitude().doubleValue(), orderLocationVo.getLatitude().doubleValue(), orderLocationVo.getLongitude().doubleValue());

        // 判断计算出的距离是否超过系统允许的最大距离阈值
        // 如果配送员距离起始点太远，无法开始服务
        if(distance > SystemConstant.DRIVER_START_LOCATION_DISTION) {
            // 抛出位置错误异常，提示配送员距离起始点过远
            throw new PowerException(ResultCodeEnum.DRIVER_START_LOCATION_DISTION_ERROR);
        }
         */
        return orderInfoFeignClient.driverArriveStartLocation(orderId, driverId).getData();
    }

    /**
     * 配送员抢单
     *
     * @param driverId 配送员ID
     * @param orderId  订单ID
     * @return 是否抢单成功
     */
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        return orderInfoFeignClient.robNewOrder(driverId, orderId).getData();
    }

    /**
     * 更新订单车辆信息
     *
     * @param updateOrderCartForm 更新订单车辆表单
     * @return 是否更新成功
     */
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        return orderInfoFeignClient.updateOrderCart(updateOrderCartForm).getData();
    }

    /**
     * 配送员开始配送服务
     *
     * @param startDriveForm 开始配送服务表单
     * @return 是否开始配送成功
     */
    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        return orderInfoFeignClient.startDrive(startDriveForm).getData();
    }

    /**
     * 配送员结束配送
     * 1.获取订单信息
     * 2.计算订单实际里程
     * 3.计算实际费用
     * 4.等候时间
     * 5.订单总金额
     * 6.系统奖励
     * 7.分账信息
     * 8.更新相关数据库表
     * 结束订单服务并完成费用结算
     * 整合订单相关的各种费用计算，包括基础费用、奖励和利润分成，并提交最终结算结果
     *
     * @param orderFeeForm 订单费用表单，包含司机输入的额外费用信息（过桥费、停车费等）
     * @return 操作是否成功完成
     */
    @Override
    public Boolean endDrive(OrderFeeForm orderFeeForm) {
        // 1. 获取订单详细信息
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderFeeForm.getOrderId()).getData();
        // 2. 计算订单的实际行驶距离
        BigDecimal realDistance = locationFeignClient.calculateOrderRealDistance(orderFeeForm.getOrderId()).getData();

        /*
        // 计算订单终点位置与服务结束时司机位置的距离
        // 参数1-2：订单终点的纬度和经度
        // 参数3-4：司机服务结束时的位置纬度和经度
        double distance = LocationUtil.getDistance(orderInfo.getEndPointLatitude().doubleValue(), orderInfo.getEndPointLongitude().doubleValue(), orderServiceLastLocationVo.getLatitude().doubleValue(), orderServiceLastLocationVo.getLongitude().doubleValue());

        // 判断计算出的距离是否超过系统允许的最大距离阈值
        // 如果距离超过阈值，表示司机未到达指定终点位置
        if(distance > SystemConstant.DRIVER_START_LOCATION_DISTION) {
            // 抛出位置错误异常，提示司机未到达终点位置
            throw new PowerException(ResultCodeEnum.DRIVER_END_LOCATION_DISTION_ERROR);
        }
         */

        // 3. 计算订单基础费用
        FeeRuleRequestForm feeRuleRequestForm = new FeeRuleRequestForm();
        // 设置实际行驶距离
        feeRuleRequestForm.setDistance(realDistance);
        // 设置服务开始时间
        feeRuleRequestForm.setStartTime(orderInfo.getStartServiceTime());
        // 计算等待时间（司机到达时间与接单时间的差值，转换为分钟）
        int waitMinute = Math.abs((int) (orderInfo.getArriveTime().getTime() - orderInfo.getAcceptTime().getTime()) / (1000 * 60));
        feeRuleRequestForm.setWaitMinute(waitMinute);
        // 调用费用规则服务计算基础费用
        FeeRuleResponseVo feeRuleResponseVo = feeRuleFeignClient.calculateOrderFee(feeRuleRequestForm).getData();
        // 计算总金额：基础费用 + 过桥费 + 停车费 + 其他费用 + 优惠费用
        BigDecimal totalAmount = feeRuleResponseVo.getTotalAmount()
                .add(orderFeeForm.getTollFee())//过桥费
                .add(orderFeeForm.getParkingFee())//停车费
                .add(orderFeeForm.getOtherFee())//其他费用
                .add(orderInfo.getFavourFee());//优惠费用
        // 更新总金额到费用响应对象中
        feeRuleResponseVo.setTotalAmount(totalAmount);

        // 4. 计算订单奖励
        // 格式化时间字符串，用于查询订单数量
        String startTime = new DateTime(orderInfo.getStartServiceTime()).toString("yyyy-MM-dd HH:mm:ss");
        String endTime = new DateTime(orderInfo.getEndServiceTime()).toString("yyyy-MM-dd HH:mm:ss");
        // 查询指定时间范围内的订单数量（用于判断奖励条件）
        Long orderNum = orderInfoFeignClient.getOrderNumByTime(startTime, endTime).getData();
        RewardRuleRequestForm rewardRuleRequestForm = new RewardRuleRequestForm();//奖励规则请求表单
        rewardRuleRequestForm.setStartTime(orderInfo.getStartServiceTime());//配送时间
        rewardRuleRequestForm.setOrderNum(orderNum);//订单数量
        // 调用奖励规则服务计算订单奖励
        RewardRuleResponseVo rewardRuleResponseVo = rewardRuleFeignClient.calculateOrderRewardFee(rewardRuleRequestForm).getData();

        // 5. 计算利润分成
        ProfitsharingRuleRequestForm profitsharingRuleRequestForm = new ProfitsharingRuleRequestForm();
        profitsharingRuleRequestForm.setOrderNum(orderNum);//订单数量
        profitsharingRuleRequestForm.setOrderAmount(totalAmount);//订单金额
        // 调用利润分成规则服务计算分成金额
        ProfitsharingRuleResponseVo profitsharingRuleResponseVo = profitsharingRuleFeignClient.calculateOrderProfitsharingFee(profitsharingRuleRequestForm).getData();

        // 6. 组装订单结算表单
        UpdateOrderBillForm updateOrderBillForm = new UpdateOrderBillForm();
        // 设置订单ID和司机ID
        updateOrderBillForm.setOrderId(orderFeeForm.getOrderId());//订单ID
        updateOrderBillForm.setDriverId(orderFeeForm.getDriverId());//配送员ID
        // 设置额外费用
        updateOrderBillForm.setTollFee(orderFeeForm.getTollFee());//过桥费
        updateOrderBillForm.setParkingFee(orderFeeForm.getParkingFee());//停车费
        updateOrderBillForm.setOtherFee(orderFeeForm.getOtherFee());//其他费用
        // 设置优惠费用
        updateOrderBillForm.setFavourFee(orderInfo.getFavourFee());//优惠费用
        // 设置实际行驶距离
        updateOrderBillForm.setRealDistance(realDistance);//实际行驶距离
        // 复制奖励规则响应的属性到结算表单
        BeanUtils.copyProperties(rewardRuleResponseVo, updateOrderBillForm);//奖励规则响应属性复制到结算表单
        // 复制费用规则响应的属性到结算表单
        BeanUtils.copyProperties(feeRuleResponseVo, updateOrderBillForm);//费用规则响应属性复制到结算表单
        // 设置利润分成规则ID
        updateOrderBillForm.setProfitsharingRuleId(profitsharingRuleResponseVo.getProfitsharingRuleId());//利润分成规则ID

        // 7. 调用订单服务完成最终结算
        orderInfoFeignClient.endDrive(updateOrderBillForm);
        // 返回操作成功结果
        return true;
    }
}
